import { quat, Quat, v3, Vec3, Mat4, v4, Vec4 } from "cc";
import GameConfig from "./GameConfig";
import { GlobalEnum } from "./GlobalEnum";
import { TreeData } from "./treeData";
import LevelCollerDataTemplate from "./LevelCollerDataTemplate";
import { SceneStyle } from "./SceneStyle";
import EventManager from "../Common/EventManager";
import { EventType } from "./GameEventType";
import Loader from "../Common/Loader";

const halfPI = Math.PI * 0.5;
const R2D = 180 / Math.PI;
const D2R = Math.PI / 180;
let tempTransform = {
    pos: v3(),
    quat: quat(),
    eulerAngles: v3(),
    sinX: 0,
    cosX: 1,
    sinY: 0,
    cosY: 1,
};
const q_a = new Quat();
const q_b = new Quat();

export default class MapData {

    /****************************************************************路段数据****************************************************************/
    /**当前随机生成的路段所属的关卡 */
    protected static curLevel: number = null;
    /**
     * 当前生成的地图数据，记录每一段路的Z轴起点坐标、路段形状
     */
    protected static curMapData: any[] = [];
    /**结尾路段 */
    protected static endPath: PathLL = null;
    protected static startLen: number = 50;
    /**路段总长度 */
    protected static totalLen: number = 0;
    /**
     * Z坐标对应的路段偏移与旋转数据
     * dis:     Math.round(-z)
     * pos:     坐标偏移
     * quat:    旋转四元素
     * eulerAngles:旋转欧拉角
     * sinX:    X轴旋转角度正弦值
     */
    protected static mapTransform: {
        [dis: number]: {
            pos: Vec3,
            quat: Quat,
            eulerAngles: Vec3,
            //上一角度相对本角度的偏移值
            sinX: number,
            cosX: number,
            sinY: number,
            cosY: number
        }
    } = {};
    /**需要传递给材质球的路径数据 */
    protected static matData: Vec4[] = [];
    // protected static matData: Mat4[] = [];

    public static getCurDataLevel() {
        return this.curLevel;
    }
    /**创建一组随机地图数据，将一直缓存直到再次生成随机地图 */
    public static createRandomMap(lv: number) {
        if (this.curLevel === lv && !!this.curMapData) {
            return;
        }
        this.curLevel = lv;
        //获取关卡障碍物数据
        this.randomLevelItem();
        //创建数据
        this.curMapData = [];
        //第一段路为直线
        this.curMapData.push(this.randomLL({
            startZ: 0,
            startPos: v3(0, 0, 0),
            quat: quat(0, Math.sin(Math.PI * 0.25), 0, Math.sin(Math.PI * 0.25)),
            len: this.startLen,
        }));
        let maxLen = this.totalLen;
        let totalLen = this.curMapData[0].len;
        GameConfig.GameRule.pathLen = Math.floor(maxLen / 10) - 10;
        if (GameConfig.GameRule.pathLen < 50) {
            GameConfig.GameRule.pathLen = 50;
        }
        GameConfig.GameRule.pathRandomLen = 20;


        let count = 9;//路段最大数量-1，最后一段路按规则添加
        //上一CL路段的弯曲方向，0：未知；-1：逆时针；1：顺时针
        let preCLwise: number = 0;
        //上一LC路段的弯曲方向，0：未知；-1：逆时针；1：顺时针
        let preLCwise: number = 0;
        for (let i = 1; i < count; ++i) {
            let prePath = this.curMapData[i - 1];
            let endAngleX = Math.abs(prePath.endEulerAngles.x);
            switch (prePath.type) {
                case GlobalEnum.PathType.LL: {
                    if (endAngleX < 1) {
                        let random = Math.random();
                        if (random < 0.8) {
                            this.addPathLC(prePath, preLCwise);
                        } else {
                            this.addPathCL(prePath, preCLwise);
                        }
                    } else {
                        this.addPathCL(prePath, preCLwise);
                    }
                    break;
                }
                case GlobalEnum.PathType.LC: {
                    let random = Math.random();
                    if (random < 0.1) {
                        this.addPathLL(prePath);
                    } else if (random < 0.7) {
                        this.addPathCL(prePath, preCLwise);
                    } else {
                        this.addPathLC(prePath, preLCwise);
                    }
                    break;
                }
                case GlobalEnum.PathType.CL: {
                    if (endAngleX < 1) {
                        let random = Math.random();
                        if (random < 0.8) {
                            this.addPathLC(prePath, preLCwise);
                        } else if (random < 0.9) {
                            this.addPathCL(prePath, preCLwise);
                        } else {
                            this.addPathLL(prePath);
                        }
                    } else {
                        let random = Math.random();
                        if (random < 0.7) {
                            this.addPathCL(prePath, preCLwise);
                        } else {
                            this.addPathLL(prePath);
                        }
                    }
                    break;
                }
            }
            totalLen += this.curMapData[i].len;
            if (totalLen > maxLen) {
                break;
            }
            //记录弯曲路段的弯曲方向
            let lastPath = this.curMapData[i];
            switch (lastPath.type) {
                case GlobalEnum.PathType.LC: {
                    preLCwise = lastPath.isClockwise ? 1 : -1;
                    break;
                }
                case GlobalEnum.PathType.CL: {
                    if (Math.abs(lastPath.endEulerAngles.x) < 1) {
                        preCLwise = 0;
                    } else {
                        preCLwise = lastPath.isClockwise ? 1 : -1;
                    }
                    break;
                }
            }
        }
        if (this.totalLen < totalLen) {
            this.totalLen = totalLen;
        }
        this.addLastPath(preLCwise, preCLwise);
        this.createEndPath();
        this.createMapTransform();
        this.createMatData();
        this.randomSceneStyle();
        EventManager.emit(EventType.LevelEvent.mapDataCreateFinish);
    }
    //添加最后一段路，将路段引向水平
    protected static addLastPath(preLCwise, preCLwise) {
        let path = this.curMapData[this.curMapData.length - 1];
        let len = this.totalLen - (path.len - path.startZ);
        if (len < GameConfig.GameRule.pathLen) {
            len = GameConfig.GameRule.pathLen;
        }
        switch (path.type) {
            case GlobalEnum.PathType.CL: {
                let x = path.endEulerAngles.x;
                if (Math.abs(x) < 1) {
                    this.addPathLC(path, preLCwise, len);
                } else {
                    this.addPathCL(path, preCLwise, true, len);
                }
                break;
            }
            case GlobalEnum.PathType.LC: {
                this.addPathLC(path, preLCwise, len);
                break;
            }
            case GlobalEnum.PathType.LL: {
                let x = path.endEulerAngles.x;
                if (Math.abs(x) < 1) {
                    this.addPathLC(path, preLCwise, len);
                } else {
                    this.addPathCL(path, preCLwise, true, len);
                }
                break;
            }
        }
        path = this.curMapData[this.curMapData.length - 1];
        len = path.len - path.startZ;
        this.totalLen = len;
    }
    protected static createEndPath() {
        let lastPath = this.curMapData[this.curMapData.length - 1];
        this.endPath = {
            type: GlobalEnum.PathType.LL,
            startZ: -this.totalLen,
            len: 1000,
            startPos: v3(lastPath.endPos),
            quat: quat(lastPath.endQuat),
            eulerAngles: v3(lastPath.endEulerAngles),
            endPos: v3(),
            endQuat: quat(lastPath.endQuat),
            endEulerAngles: v3(lastPath.endEulerAngles),
            offset: v3(0, 0, 0),
        };

        this.endPath.offset.z = -this.endPath.len;
        Quat.fromEuler(q_a, this.endPath.endEulerAngles.x, this.endPath.endEulerAngles.y - 90, 0);
        Vec3.transformQuat(this.endPath.offset, this.endPath.offset, q_a);

        this.endPath.endPos.x = this.endPath.startPos.x + this.endPath.offset.x;
        this.endPath.endPos.y = this.endPath.startPos.y + this.endPath.offset.y;
        this.endPath.endPos.z = this.endPath.startPos.z + this.endPath.offset.z;
    }

    /**
     * 根据Z坐标获取对应的坐标偏移与旋转四元数
     * @param z 顶点Z轴坐标
     */
    public static getTransform(z: number) {
        if (z < -this.totalLen) {
            let tr = this.computeTransform(z);
            tr.sinX = 0;
            tr.cosX = 1;
            tr.sinY = 0;
            tr.cosY = 1;
            return tr;
        }
        if (z > 0) {
            z = 0;
        } else {
            z = Math.round(-z);
        }
        return this.mapTransform[z];
    }
    /**
     * 根据顶点Z轴坐标获取对应的坐标偏移和旋转四元数
     * @param z 顶点Z坐标
     * @returns 只读对象，包含坐标偏移与旋转四元数
     */
    public static computeTransform(z: number) {
        // if (z > 0) {
        //     z = 0;
        // } else if (z < -this.totalLen) {
        //     z = -this.totalLen;
        // }
        if (z < -this.totalLen) {
            return this.getLL(z, this.endPath);
        }
        let index = this.getDataIndex(z);
        let data = this.curMapData[index];
        switch (data.type) {
            case GlobalEnum.PathType.CL: {
                return this.getCL(z, data);
            }
            case GlobalEnum.PathType.LL: {
                return this.getLL(z, data);
            }
            case GlobalEnum.PathType.LC: {
                return this.getLC(z, data);
            }
        }
    }
    /**获取材质球需要的参数 */
    public static getMatData() {
        return this.matData;
    }
    /**关卡路段总长 */
    public static getTotalLen() {
        return this.totalLen;
    }
    /**关卡中的物体 */
    public static getLevelItem() {
        return {
            barrierGroups: this.barrierGroups,
            leftBarrierGroups: this.leftBarrierGroups,
            rightBarrierGroups: this.rightBarrierGroups,
            wallBarrierGroups: this.wallBarrierGroups,
            lunTaiGroups: this.lunTaiGroups,
            golds: this.golds,
            carParts: this.carParts,
            carParts2: this.carParts2,
            terrains: this.terrains,
            changeCarQuad: this.changeCarQuad,
            suiDao: this.suiDao,
            shiTous: this.shiTous,
            trees: this.trees,
        };
    }

    //#region 随机生成路段
    //#region 根据上一路段随机生成下一路段
    protected static addPathLC(prePath, preWise: number, len?: number) {
        let nextPathData = this.getNextPathDataLC(prePath);
        if (preWise != 0) {
            nextPathData.isClockwise = preWise == -1;
        }
        if (undefined !== len) {
            nextPathData.len = len;
        }
        this.curMapData.push(this.randomLC(nextPathData));
    }
    protected static addPathCL(prePath, preWise: number, toH: boolean = false, len?: number) {
        let nextPathData = this.getNextPathDataCL(prePath);
        if (preWise != 0) {
            nextPathData.isClockwise = preWise == -1;
        }
        if (toH) {
            nextPathData.radian = Math.abs(nextPathData.radianX);
        }
        if (undefined !== len) {
            nextPathData.len = len;
        }
        this.curMapData.push(this.randomCL(nextPathData));
    }
    protected static addPathLL(prePath) {
        this.curMapData.push(this.randomLL(this.getNextPathDataLL(prePath)));
    }
    //#endregion

    //#region 随机生成路段数据
    /**随机路段数据：侧视直线，俯视直线 */
    protected static randomLL(data: { startZ: number, startPos: Vec3, quat: Quat, len?: number }) {
        let path: PathLL = {
            type: GlobalEnum.PathType.LL,
            startZ: data.startZ,
            len: GameConfig.GameRule.pathLen + Math.random() * GameConfig.GameRule.pathRandomLen,
            startPos: v3(data.startPos),
            quat: quat(data.quat),
            eulerAngles: v3(),
            endPos: v3(),
            endQuat: quat(data.quat),
            endEulerAngles: v3(),
            offset: v3(0, 0, 0),
        };
        if (undefined !== data.len) {
            path.len = data.len;
        }
        data.quat.getEulerAngles(path.eulerAngles);
        path.endEulerAngles.set(path.eulerAngles);

        path.offset.z = -path.len;
        Quat.fromEuler(q_a, path.endEulerAngles.x, path.endEulerAngles.y - 90, 0);
        Vec3.transformQuat(path.offset, path.offset, q_a);
        // path.offset.normalize().multiplyScalar(path.len);
        path.endPos.x = path.startPos.x + path.offset.x;
        path.endPos.y = path.startPos.y + path.offset.y;
        path.endPos.z = path.startPos.z + path.offset.z;
        return path;
    }
    /**随机路段数据：侧视水平直线，俯视圆弧 */
    protected static randomLC(data: { startZ: number, startPos: Vec3, radianY: number, isClockwise?: boolean, len?: number }) {
        let path: PathLC = {
            type: GlobalEnum.PathType.LC,
            startZ: data.startZ,
            len: GameConfig.GameRule.pathLen + Math.random() * GameConfig.GameRule.pathRandomLen,
            centerPos: v3(),
            radius: 1,
            isClockwise: false,
            startRadian: 0,
            startPos: v3(data.startPos),
            startQuat: quat(),
            startEulerAngles: v3(),
            endPos: v3(),
            endQuat: quat(),
            endEulerAngles: v3(),
            lineRadian: 0,
        };
        if (undefined !== data.len) {
            path.len = data.len;
        }
        if (this.curLevel <= 5) {
            path.radius = path.len;
        } else {
            let minRadius = path.len / 2;
            let maxRadius = path.len / 1.5;
            path.radius = Math.random() * (maxRadius - minRadius) + minRadius;
        }
        if (undefined !== data.isClockwise) {
            path.isClockwise = data.isClockwise;
        } else {
            path.isClockwise = Math.random() > 0.5;
        }
        if (path.isClockwise) {
            path.startRadian = data.radianY + halfPI;
        } else {
            path.startRadian = data.radianY - halfPI;
        }
        let r = path.startRadian - Math.PI;
        path.centerPos.x = path.startPos.x + path.radius * Math.cos(r);
        path.centerPos.y = path.startPos.y;
        path.centerPos.z = path.startPos.z - path.radius * Math.sin(r);
        r = data.radianY * 0.5;
        path.startQuat.y = Math.sin(r);
        path.startQuat.w = Math.cos(r);
        path.startQuat.getEulerAngles(path.startEulerAngles);
        //终点
        if (path.isClockwise) {
            r = path.startRadian - path.len / path.radius;
        } else {
            r = path.startRadian + path.len / path.radius;
        }
        path.endPos.x = path.centerPos.x + path.radius * Math.cos(r);
        path.endPos.y = path.centerPos.y;
        path.endPos.z = path.centerPos.z - path.radius * Math.sin(r);
        if (path.isClockwise) {
            r -= halfPI;
        } else {
            r += halfPI;
        }
        path.endQuat.y = Math.sin(r * 0.5);
        path.endQuat.w = Math.cos(r * 0.5);
        path.endQuat.getEulerAngles(path.endEulerAngles);
        // console.log(path);
        return path;
    }
    /**随机路段数据：侧视圆弧，俯视直线 */
    protected static randomCL(data: { startZ: number, startPos: Vec3, radianX: number, radianY: number, isClockwise?: boolean, radian?: number, len?: number }) {
        let path: PathCL = {
            type: GlobalEnum.PathType.CL,
            startZ: data.startZ,
            // len: 30,//todo
            len: GameConfig.GameRule.pathLen + Math.random() * GameConfig.GameRule.pathRandomLen,
            centerPos: v3(),
            radius: 1,
            isClockwise: false,
            startRadian: 0,
            startPos: v3(data.startPos),
            startQuat: quat(),
            startEulerAngles: v3(),
            endPos: v3(),
            endQuat: quat(),
            endEulerAngles: v3(),
            lineRadian: data.radianY,
        };
        if (undefined !== data.len) {
            path.len = data.len;
        }

        path.centerPos.x = data.startPos.x;
        //半径
        let radian = 0;
        if (undefined !== data.radian) {
            radian = data.radian;
        } else {
            radian = Math.abs(data.radianX) + 0.3 + Math.random() * 0.8;
            if (Math.abs(data.radianX) > 0.4 && Math.random() < 10.7) {
                radian = Math.abs(data.radianX);
            } else if (radian < 0.5) {
                radian = 0.5;
            }
        }
        path.radius = path.len / radian;
        //方向
        if (undefined !== data.isClockwise) {
            path.isClockwise = data.isClockwise;
        } else if (data.radianX > 0) {
            path.isClockwise = true;
        } else if (data.radianX < 0) {
            path.isClockwise = false;
        } else {
            path.isClockwise = Math.random() > 0.5;
        }

        let r = 0;//终点到圆心连线与Z轴负向的夹角弧度
        if (path.isClockwise) {
            path.startRadian = data.radianX + halfPI;
            path.centerPos.z = data.startPos.z + Math.cos(path.startRadian) * path.radius;
            r = path.startRadian - radian;
        } else {
            path.startRadian = data.radianX - halfPI;
            path.centerPos.z = path.startPos.z + path.radius * Math.cos(path.startRadian);
            r = path.startRadian + radian;
        }

        path.centerPos.y = path.startPos.y - path.radius * Math.sin(path.startRadian);
        path.startEulerAngles.x = data.radianX * R2D;
        path.startEulerAngles.y = data.radianY * R2D;
        Quat.fromEuler(path.startQuat, path.startEulerAngles.x, path.startEulerAngles.y, path.startEulerAngles.z);

        //终点
        let l = path.startPos.z - (path.centerPos.z - path.radius * Math.cos(r));//终点到起点的Z轴距离
        path.endPos.x = path.startPos.x + l * Math.cos(path.lineRadian);
        path.endPos.y = path.centerPos.y + path.radius * Math.sin(r);
        path.endPos.z = path.startPos.z - l * Math.sin(path.lineRadian);
        if (path.isClockwise) {
            path.endEulerAngles.x = r * R2D - 90;
        } else {
            path.endEulerAngles.x = r * R2D + 90;
        }
        path.endEulerAngles.y = path.lineRadian * R2D;
        Quat.fromEuler(path.endQuat, path.endEulerAngles.x, path.endEulerAngles.y, path.endEulerAngles.z);

        return path;
    }
    //#endregion

    //#region 获取生成下一路段需要的数据
    protected static getNextPathDataLL(path) {
        let data = {
            startZ: path.startZ - path.len,
            startPos: v3(path.endPos),
            quat: path.endQuat,
        };
        return data;
    }
    protected static getNextPathDataLC(path) {
        let data = {
            startZ: path.startZ - path.len,
            startPos: v3(path.endPos),
            radianY: path.endEulerAngles.y * D2R,
        };
        return data;
    }
    protected static getNextPathDataCL(path) {
        let data = {
            startZ: path.startZ - path.len,
            startPos: v3(path.endPos),
            radianX: path.endEulerAngles.x * D2R,
            radianY: path.endEulerAngles.y * D2R,
        };
        return data;
    }
    //#endregion
    //#endregion

    //#region 预计算偏移数据
    protected static createMapTransform() {
        this.mapTransform = {};
        let tr0 = this.computeTransform(0);
        this.mapTransform[0] = {
            pos: v3(tr0.pos),
            quat: quat(tr0.quat),
            eulerAngles: v3(tr0.eulerAngles),
            sinX: 0,
            cosX: 1,
            sinY: 0,
            cosY: 1,
        };
        let len = Math.ceil(this.totalLen);
        for (let z = 1; z <= len; ++z) {
            let t = this.computeTransform(-z);
            let pre = this.mapTransform[z - 1];
            this.mapTransform[z] = {
                pos: v3(t.pos),
                quat: quat(t.quat),
                eulerAngles: v3(t.eulerAngles),
                //相对上一角度的偏移值：
                sinX: Math.sin((pre.eulerAngles.x - t.eulerAngles.x) * D2R),
                cosX: Math.cos((pre.eulerAngles.x - t.eulerAngles.x) * D2R),
                sinY: Math.sin((pre.eulerAngles.y - t.eulerAngles.y) * D2R),
                cosY: Math.cos((pre.eulerAngles.y - t.eulerAngles.y) * D2R),
            };
        }
    }
    protected static getDataIndex(z: number) {
        for (let i = this.curMapData.length - 1; i >= 0; --i) {
            if (z <= this.curMapData[i].startZ) {
                return i;
            }
        }
        return 0;
    }
    //侧视圆弧，俯视直线
    protected static getCL(z: number, data: PathCL) {
        let len = data.startZ - z;
        let radian = len / data.radius;
        if (data.isClockwise) {
            radian = data.startRadian - radian;
        } else {
            radian += data.startRadian;
        }
        let offsetY = data.radius * Math.sin(radian) + data.centerPos.y;
        let offsetZ = -data.radius * Math.cos(radian) + data.centerPos.z;
        let offsetX = (data.startPos.z - offsetZ) * Math.cos(data.lineRadian) + data.startPos.x;
        offsetZ = -(data.startPos.z - offsetZ) * Math.sin(data.lineRadian) + data.startPos.z;

        tempTransform.pos.x = offsetX;
        tempTransform.pos.y = offsetY;
        tempTransform.pos.z = offsetZ;

        let angleX = radian - halfPI;
        if (!data.isClockwise) {
            angleX = radian + halfPI;
        }
        angleX *= R2D;
        let angleY = data.lineRadian - halfPI;
        angleY *= R2D;
        Quat.fromEuler(tempTransform.quat, angleX, angleY, 0);

        tempTransform.eulerAngles.x = angleX;
        tempTransform.eulerAngles.y = angleY;
        tempTransform.eulerAngles.z = 0;

        return tempTransform;
    }
    //侧视直线，俯视直线：先按侧视旋转，再按俯视旋转
    protected static getLL(z: number, data: PathLL) {
        //侧视直线：
        let len = data.startZ - z;
        let r = len / data.len;
        tempTransform.pos.x = data.startPos.x + data.offset.x * r;
        tempTransform.pos.y = data.startPos.y + data.offset.y * r;
        tempTransform.pos.z = data.startPos.z + data.offset.z * r;
        Quat.fromEuler(tempTransform.quat, data.endEulerAngles.x, data.endEulerAngles.y - 90, 0);
        tempTransform.eulerAngles.set(data.endEulerAngles);
        tempTransform.eulerAngles.y -= 90;
        return tempTransform;
    }
    //侧视直线，俯视圆弧
    protected static getLC(z: number, data: PathLC) {
        //坐标点到圆心连线与X轴的弧度
        let len = data.startZ - z;
        let radian = len / data.radius;
        if (data.isClockwise) {
            radian = data.startRadian - radian;
        } else {
            radian += data.startRadian;
        }
        //坐标点位置偏移
        let offsetX = Math.cos(radian) * data.radius + data.centerPos.x;
        let offsetY = data.startPos.y;
        let offsetZ = -Math.sin(radian) * data.radius + data.centerPos.z;
        tempTransform.pos.x = offsetX;
        tempTransform.pos.y = offsetY;
        tempTransform.pos.z = offsetZ;

        let radianY = radian * 0.5;
        if (data.isClockwise) {
            radianY = (radian - Math.PI) * 0.5;
        }
        tempTransform.quat.x = 0;
        tempTransform.quat.y = Math.sin(radianY);
        tempTransform.quat.z = 0;
        tempTransform.quat.w = Math.cos(radianY);

        tempTransform.eulerAngles.x = 0;
        tempTransform.eulerAngles.y = radianY * 2 * R2D;
        tempTransform.eulerAngles.z = 0;
        return tempTransform;
    }
    //#endregion

    //#region 材质球需要的参数
    /**预创建材质球需要的参数 */
    protected static createMatData() {
        this.matData = [];
        let maxDis = -99999;
        for (let i = 0, c = this.curMapData.length; i * 2 < c; ++i) {
            let m4: number[] = [];
            let path = this.curMapData[i * 2];
            this._getMatData(m4, 0, path);
            if (i * 2 + 1 < c) {
                path = this.curMapData[i * 2 + 1];
                this._getMatData(m4, 8, path);
            } else {
                m4.push(0, 0, 0, maxDis, 0, 0, 0, 0);
            }
            let j = 0;
            this.matData.push(v4(m4[j++], m4[j++], m4[j++], m4[j++]));
            this.matData.push(v4(m4[j++], m4[j++], m4[j++], m4[j++]));
            this.matData.push(v4(m4[j++], m4[j++], m4[j++], m4[j++]));
            this.matData.push(v4(m4[j++], m4[j++], m4[j++], m4[j++]));
            // let mat4 = new Mat4();
            // this.matData.push(Mat4.fromArray(mat4, m4));
        }

        while (this.matData.length < 20) {
            this.matData.push(v4(0, 0, 0, maxDis));
            // let m = new Mat4();
            // m.m03 = maxDis;
            // m.m11 = maxDis;
            // this.matData.push(m);
        }

        let endM4 = [];
        let lastPath = this.curMapData[this.curMapData.length - 1];
        endM4[0] = lastPath.endPos.x;
        endM4[1] = lastPath.endPos.y;
        endM4[2] = lastPath.endPos.z;
        endM4[3] = -this.totalLen;
        Quat.fromEuler(q_a, lastPath.endEulerAngles.x, lastPath.endEulerAngles.y - 90, 0);
        endM4[4] = q_a.x;
        endM4[5] = q_a.y;
        endM4[6] = q_a.z;
        endM4[7] = q_a.w;

        // endM4[8] = lastPath.endPos.x;
        // endM4[9] = lastPath.endPos.y;
        // endM4[10] = lastPath.endPos.z;
        // endM4[11] = -this.totalLen;
        // endM4[12] = q_a.x;
        // endM4[13] = q_a.y;
        // endM4[14] = q_a.z;
        // endM4[15] = q_a.w;

        let pe1 = v4(endM4[0], endM4[1], endM4[2], endM4[3]);
        let pe2 = v4(endM4[4], endM4[5], endM4[6], endM4[7]);
        this.matData.push(pe1);
        this.matData.push(pe2);
        // let endMat4 = new Mat4();
        // this.matData.push(Mat4.fromArray(endMat4, endM4));

    }
    protected static _getMatData(m4: number[], offset: number, path) {
        switch (path.type) {
            case GlobalEnum.PathType.LL: {
                this.getMatDataLL(m4, offset, path);
                return;
            }
            case GlobalEnum.PathType.CL: {
                this.getMatDataCL(m4, offset, path);
                return;
            }
            case GlobalEnum.PathType.LC: {
                this.getMatDataLC(m4, offset, path);
                return;
            }
            default: {
                console.error("路段类型未定义：", path);
                return;
            }
        }
    }
    protected static getMatDataLL(m4: number[], offset: number, path: PathLL) {
        m4[offset + 0] = path.startPos.x;
        m4[offset + 1] = path.startPos.y;
        m4[offset + 2] = path.startPos.z;
        m4[offset + 3] = path.startZ;
        Quat.fromEuler(q_a, path.endEulerAngles.x, path.endEulerAngles.y - 90, 0);
        m4[offset + 4] = q_a.x;
        m4[offset + 5] = q_a.y;
        m4[offset + 6] = q_a.z;
        m4[offset + 7] = q_a.w;
    }
    protected static getMatDataCL(m4: number[], offset: number, path: PathCL) {
        let index = offset;
        m4[index++] = path.centerPos.x;
        m4[index++] = path.centerPos.y;
        m4[index++] = path.centerPos.z;
        m4[index++] = path.startZ;
        if (path.isClockwise) {
            m4[index++] = path.radius;
        } else {
            m4[index++] = -path.radius;
        }
        m4[index++] = path.startRadian;
        m4[index++] = path.lineRadian;
        m4[index++] = 4.0;
    }
    protected static getMatDataLC(m4: number[], offset: number, path: PathLC) {
        let index = offset;
        m4[index++] = path.centerPos.x;
        m4[index++] = path.centerPos.y;
        m4[index++] = path.centerPos.z;
        m4[index++] = path.startZ;
        if (path.isClockwise) {
            m4[index++] = path.radius;
        } else {
            m4[index++] = -path.radius;
        }
        m4[index++] = path.startRadian;
        m4[index++] = path.lineRadian;
        m4[index++] = 3.0;
    }
    //#endregion

    /****************************************************************关卡中元素****************************************************************/
    //#region 障碍物
    /**障碍物 */
    protected static barrierGroups: any[] = [];
    protected static leftBarrierGroups: any[] = [];
    protected static rightBarrierGroups: any[] = [];
    protected static wallBarrierGroups: any[] = [];
    protected static lunTaiGroups: any[] = [];
    /**金币 */
    protected static golds: any[] = [];
    /**零件 */
    protected static carParts: any[] = [];
    protected static carParts2: any[] = [];
    /**地形 */
    protected static terrains: any[] = [];
    /**车辆变形的面 */
    protected static changeCarQuad: any[] = [];
    /**隧道 */
    protected static suiDao: any[] = [];
    /**路旁边的石头 */
    protected static shiTous: any[] = [];
    /**树 */
    protected static trees: any[] = [];
    protected static randomLevelItem() {
        this.barrierGroups = [];
        this.golds = [];
        this.carParts = [];
        this.terrains = [];
        this.changeCarQuad = [];
        this.suiDao = [];
        this.shiTous = [];
        this.trees = [];

        let allData = LevelCollerDataTemplate.getData();
        let data = allData[this.curLevel];
        if (!data) {
            let keys = Object.keys(allData);
            let index = Math.floor(Math.random() * (keys.length - 4.01)) + 4;//+1:不随机第一关的数据
            data = allData[keys[index]];
        }

        this.totalLen = data.totalLen;

        this.leftBarrierGroups = data.LeftBarrierGroup || [];
        this.rightBarrierGroups = data.RightBarrierGroup || [];
        this.wallBarrierGroups = data.WallBarrierGroup || [];
        this.lunTaiGroups = data.LunTaiGroup || [];

        this.golds = data.Gold || [];

        this.carParts = data.CarPart || [];
        this.carParts2 = data.CarPart2 || [];


        this.changeCarQuad = data.ChangeCarQuad;

        for (let i = 0; i < this.changeCarQuad.length - 1; ++i) {
            let z = this.changeCarQuad[i].z;
            let z2 = this.changeCarQuad[i + 1].z;
            this.terrains.push({ z: z - 5 });
            this.addSuiDao(z, z - z2);
        }
        this.terrains.push({ z: this.changeCarQuad[this.changeCarQuad.length - 1].z - 5 });

        this.randomShiTou();

    }
    //随机隧道
    protected static addSuiDao(z, dis) {
        let count = Math.round(Math.random() * 2);
        if (count == 0) {
            return;
        }
        //隧道长度
        let suiDaoLen = 20;
        //3个车辆提示标志占的长度
        let carIconDis = 60;
        //隧道与变形平面的最小距离
        let minDis = 20;
        if (count == 1) {
            z -= Math.random() * (dis - suiDaoLen - carIconDis - minDis) + minDis;
            this.suiDao.push({ z: z });
            return;
        }
        if (count == 2) {
            let z1 = z - Math.random() * (dis - suiDaoLen - carIconDis - minDis) - minDis;
            this.suiDao.push({ z: z1 });
            let l1 = z - z1 - minDis;
            let l2 = z1 - suiDaoLen - (z - dis + carIconDis);
            let z2 = 0;
            if (l1 > l2) {
                z2 = z - minDis - Math.random() * l1;
            } else {
                z2 = z1 - suiDaoLen - Math.random() * l2;
            }
            this.suiDao.push({ z: z2 });
        }
    }
    //石头和树
    protected static randomShiTou() {
        this.shiTous = [];
        let data = TreeData;
        let maxPtr = data.length - 0.001;
        let count = Math.ceil(this.totalLen * 0.01) + 1;
        for (let i = 0; i < count; ++i) {
            let index = Math.floor(Math.random() * maxPtr);
            this.shiTous.push(index);
        }
    }
    //#endregion

    /****************************************************************场景风格****************************************************************/
    protected static sceneStyleIndex: number = 0;
    protected static randomSceneStyle() {
        // this.sceneStyleIndex = 4;
        // return;
        let lv = this.curLevel;
        if (lv <= SceneStyle.length) {
            this.sceneStyleIndex = lv - 1;
        } else {
            this.sceneStyleIndex = Math.floor(Math.random() * (SceneStyle.length - 0.001));
        }
        // let style = this.getSceneStyleData();
        // if (!!style.bundle) {
        //     Loader.loadBundle(style.bundle, () => { }, false, false);
        // }
    }
    public static getSceneStyleData() {
        return SceneStyle[this.sceneStyleIndex];
    }

}
/**侧视直线，俯视直线 */
export type PathLL = {
    type: string,
    startZ: number,
    len: number,
    startPos: Vec3,
    quat: Quat,
    eulerAngles: Vec3,
    endPos: Vec3,
    endQuat: Quat,
    endEulerAngles: Vec3,
    //终点相对起点的偏移量
    offset: Vec3,
}
/**侧视圆弧，俯视直线 */
export type PathCL = {
    type: string,
    startZ: number,
    len: number,
    //圆弧圆心坐标
    centerPos: Vec3,
    //圆弧半径
    radius: number,
    //是否顺时针
    isClockwise: boolean,
    /**圆弧起点与圆心的连线与Z轴负向夹角弧度 */
    startRadian: number,

    //起点坐标
    startPos: Vec3,
    startQuat: Quat,
    startEulerAngles: Vec3,

    endPos: Vec3,
    endQuat: Quat,
    endEulerAngles: Vec3,

    //侧视直线与X轴正向夹角弧度
    lineRadian: number,
}
/**侧视水平直线，俯视圆弧 */
export type PathLC = {
    type: string,
    startZ: number,
    len: number,
    //圆弧圆心坐标
    centerPos: Vec3,
    //圆弧半径
    radius: number,
    //是否顺时针
    isClockwise: boolean,
    /**圆弧起点与圆心的连线与X轴正向夹角弧度 */
    startRadian: number,

    //起点坐标
    startPos: Vec3,
    startQuat: Quat,
    startEulerAngles: Vec3,

    endPos: Vec3,
    endQuat: Quat,
    endEulerAngles: Vec3,

    //侧视直线与Z轴负向夹角弧度
    lineRadian: number,
}
enum levelItemType {
    barrier,
    gold,
    carPart,
}
